/*******************************************************************************
 * Copyright (c) 2010 European Software Institute - Tecnalia.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Author - Adrian Noguero (adrian.noguero@tecnalia.com)
 *     
 *******************************************************************************/
package es.esi.gemde.modeltransformator.service.impl;

import java.util.HashMap;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.plugin.AbstractUIPlugin;

import es.esi.gemde.modeltransformator.service.AbstractJavaTransformation;
import es.esi.gemde.modeltransformator.service.ITransformationEngine;

/**
 * The manager of the transformation engine repository in GEMDE.
 * It is a singleton.
 *
 * @author Adrian Noguero (adrian.noguero@tecnalia.com)
 * @version 1.0
 * @since 1.0
 *
 */
public class EngineRepository {

	/**
	 * The shared instance of the repository.
	 */
	private static final EngineRepository instance = new EngineRepository();
	/**
	 * A constant defining the ID of the extension point for transformation engines.
	 */
	private final String ENGINE_EXTENSION_ID = "es.esi.gemde.modeltransformator.transformationengine";
	private HashMap<String,ITransformationEngine> engines = new HashMap<String,ITransformationEngine>();
	private HashMap<String,Image> icons = new HashMap<String, Image>();
	
	
	/**
	 * Returns the instance of the Engine Repository.
	 * 
	 * @return the shared repository instance.
	 */
	public static EngineRepository getInstance() {
		return instance;
	}
	
	/**
	 * This method initializes the repository with the transformation 
	 * engines contributed in the extension point defined by {@link EngineRepository#ENGINE_EXTENSION_ID}.
	 * 
	 */
	public void initializeEngines() {
		
		// Add the built-in JavaEngine to the engines list
		JavaTransformationEngine jte = new JavaTransformationEngine();
		EngineRepository.getInstance().registerEngine(jte);
		
		// Get the elements contributing in the extension point
		IConfigurationElement[] config = Platform.getExtensionRegistry().getConfigurationElementsFor(ENGINE_EXTENSION_ID);
		try {
			for (IConfigurationElement e : config) {
				final Object engine = e.createExecutableExtension("class");
				
				// Only if the class is a ITransformationEngine instance
				if (engine instanceof ITransformationEngine && ((ITransformationEngine)engine).getName() != null && !((ITransformationEngine)engine).getName().equals("") && !((ITransformationEngine)engine).getName().equals(AbstractJavaTransformation.ENGINE_NAME)) {
					registerEngine((ITransformationEngine)engine);
					
					// Get the selected icon from the contributing plug-in
					ImageDescriptor icon = AbstractUIPlugin.imageDescriptorFromPlugin(e.getContributor().getName(), "/" + e.getAttribute("icon"));
					if (icon != null) {
						icons.put(((ITransformationEngine)engine).getName(), icon.createImage());
					}
				}
			}
		} catch (CoreException ex) {
			ex.printStackTrace();
		}

	}
	
	/**
	 * This method registers a new engine in the repository.
	 * Nothing will be done if the name of the provided engine is already in use.
	 * 
	 * @param newEngine the engine instance to be registered.
	 */
	public void registerEngine(ITransformationEngine newEngine) {
		if (!engines.containsKey(newEngine.getName())) {
			engines.put(newEngine.getName(), newEngine);
		}
	}
	
	/**
	 * The method unregisters the engine with the given name from the repository.
	 * If the provided name is not found, then nothing will be done.
	 * 
	 * @param engineName the name of the engine to be unregistered.
	 */
	public void unregisterEngine(String engineName) {
		if (engines.containsKey(engineName)) {
			engines.remove(engineName);
		}
	}
	
	/**
	 * Returns the instance of a transformation engine given its name.
	 * 
	 * @param name the name of the transformation engine.
	 * @return the instance that matches the provided name or null if the engine name provided is not registered.
	 */
	public ITransformationEngine getEngineByName(String name) {
		return engines.get(name);
	}
	
	/**
	 * Returns an array with all the transformation engines registered in the repository.
	 * 
	 * @return the array with the transformation engines.
	 */
	public ITransformationEngine [] getEngines() {
		return engines.values().toArray(new ITransformationEngine[0]);
	}
	
	/**
	 * Returns an array with all the names of the transformation engines registered in the repository.
	 * 
	 * @return the array of strings containing the names of the engines.
	 */
	public String [] getEngineNames() {
		return engines.keySet().toArray(new String[0]);
	}
	
	/**
	 * Returns the icon image related to a specific transformation engine
	 * 
	 * @param name the name of the engine.
	 * @return the icon image.
	 */
	public Image getEngineImage(String name) {
		return icons.get(name);
	}
	
}
